package com.example.demo;

import com.example.api.JobApi;
import com.example.api.JobExecutor;
import com.example.api.dto.ExecuteUserDTO;
import com.example.api.dto.TiggerDTO;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.firenio.codec.http11.*;
import com.firenio.component.Channel;
import com.firenio.component.Frame;
import com.firenio.component.IoEventHandle;

import java.io.IOException;
import java.util.Map;

/**
 * @author fanhang
 */
public class FirenioHandler extends IoEventHandle {
    private final HttpFrame frame404 = new HttpFrame();

    private final JsonMapper jsonMapper;
    private final JobExecutor jobExecutor;

    public FirenioHandler(JsonMapper jsonMapper, JobExecutor jobExecutor) throws JsonProcessingException {
        this.jsonMapper = jsonMapper;
        this.jobExecutor = jobExecutor;
        frame404.setResponseHeader(HttpHeader.Server, HttpStatic.server_firenio_bytes);
        frame404.setContentType(HttpContentType.application_json);
        frame404.setStatus(HttpStatus.C404);
        frame404.setContent(jsonMapper.writeValueAsBytes(Map.of("message", "404")));
    }

    @Override
    public void accept(Channel channel, Frame frame) throws Exception {
        if (frame instanceof HttpFrame httpFrame) {
            try {
                Object data = this.dispatch(httpFrame.getRequestURL(), httpFrame.getBytesContent());
                this.writeFrame(channel, httpFrame, HttpStatus.C200, data);
            } catch (UnsupportedOperationException e) {
                channel.writeAndFlush(frame404);
            } catch (Exception e) {
                this.writeFrame(channel, httpFrame, HttpStatus.C500, Map.of("message", e.getMessage()));
            }
        }
        channel.writeAndFlush(frame404);
    }

    private Object dispatch(String uri, byte[] data) {
        if (uri.endsWith("/")) {
            uri = uri.substring(0, uri.length() - 1);
        }
        if (uri.startsWith(JobApi.EXECUTE_USER)) {
            return this.jobExecutor.executeUser(decode(data, ExecuteUserDTO.class));
        }
        if (uri.startsWith(JobApi.TIGGER)) {
            return this.jobExecutor.tigger(decode(data, TiggerDTO.class));
        }
        throw new UnsupportedOperationException("不支持");
    }

    private <T> T decode(byte[] data, Class<T> clazz) {
        try {
            return jsonMapper.readValue(data, clazz);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void writeFrame(Channel channel, HttpFrame frame, HttpStatus status, Object data) throws Exception {
        frame.setResponseHeader(HttpHeader.Server, HttpStatic.server_firenio_bytes);
        frame.setContentType(HttpContentType.application_json);
        frame.setStatus(status);
        frame.setContent(jsonMapper.writeValueAsBytes(data));
        channel.writeAndFlush(frame);
    }
}
